#pragma once

#include <iostream>
#include <unistd.h>
#include <cstdlib>
#include <signal.h>
#include <string>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

const std::string nullfile = "/dev/null";

void Daemon(const std::string &cwd = "") // 不传参数的话就是默认把守护进程工作目录放到根目录去
{
    // 1，守护进程需要忽略其它信信号
    signal(SIGCLD, SIG_IGN);  // 直接忽略17号信号，为了防止万一出现一些读端关掉了，写端还在写的情况，守护进程
    signal(SIGPIPE, SIG_IGN); // 直接忽略13号信号
    signal(SIGSTOP, SIG_IGN); // 忽略19号暂停信号

    // 2，将自己变成独立的会话
    if (fork() > 0)
        exit(0); // 直接干掉父进程
    setsid();    // 子进程自成会话

    // 3，更改当前调用进程的工作目录
    if (!cwd.empty())
        chdir(cwd.c_str());

    // 4，不能直接关闭三个输入流，打印时会出错，Linux中有一个/dev/null 字符文件，类似垃圾桶，所有往这个文件写的数据会被直接丢弃，读也读不到
    // 所以可以把标准输入输出错误全部重定向到这个文件中
    // 如果需要就往文件里写，反正不能再打印到屏幕上了
    int fd = open(nullfile.c_str(), O_RDWR); // 以读写方式打开
    if (fd > 0)                              // 打开成功
    {
        // 把三个默认流全部重定向到垃圾桶的null的套接字里去
        dup2(fd, 0);
        dup2(fd, 1);
        dup2(fd, 2);
        close(fd);
    }
}